package com.qcit.complier

import com.google.auto.service.AutoService
import com.qcit.annotation.ACTIVITY
import com.qcit.annotation.ARouter
import com.qcit.annotation.CALL
import com.qcit.annotation.FRAGMENT
import com.qcit.annotation.bean.ARouterBean
import com.qcit.complier.utils.AProcessorConfig
import com.qcit.complier.utils.AProcessorConfig.ACTIVITY_PACKAGE
import com.qcit.complier.utils.AProcessorConfig.API_PACKAGE
import com.qcit.complier.utils.AProcessorConfig.APT_PACKAGE_DEFULT
import com.qcit.complier.utils.AProcessorConfig.AROUTER_API_GROUP
import com.qcit.complier.utils.AProcessorConfig.AROUTER_API_PATH
import com.qcit.complier.utils.AProcessorConfig.CALL_PACKAGE
import com.qcit.complier.utils.AProcessorConfig.Fragment_PACKAGE
import com.qcit.complier.utils.AProcessorConfig.GROUP_FILE_NAME
import com.qcit.complier.utils.AProcessorConfig.IAROUTERGROUP
import com.qcit.complier.utils.AProcessorConfig.IAROUTERPATH
import com.qcit.complier.utils.AProcessorConfig.METHOD_AROUTER_GROUP
import com.qcit.complier.utils.AProcessorConfig.METHOD_AROUTER_PATH
import com.qcit.complier.utils.AProcessorConfig.PATH_FILE_NAME
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types
import javax.tools.Diagnostic

//
//
///**
// * 注解解析器，每个模块都会执行一次该类中的方法
// * Created by aruba on 2021/11/22.
// */
@AutoService(Processor::class)
//指定要处理的注解
@SupportedAnnotationTypes(AProcessorConfig.AROUTER)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
class ARouterProcessor : AbstractProcessor() {
    // 日志打印
    lateinit var MSG:Messager //日志打印
    lateinit var mElement: Elements //获取节点（类，属性，方法）
    lateinit var mTypes: Types //类信息工具类，包含用于操作TypeMirror的工具方法
    lateinit var mFiler:Filer // 文件生成器， 类 资源 等，就是最终要生成的文件 是需要Filer来完成的
    var options:String? = null//模块名称
    var aptPackage = APT_PACKAGE_DEFULT//存放apt生成的类的目录
    //path 缓存
    //Map<path, List<RouterBean>>
    var mAllPathMap = mutableMapOf<String,MutableList<ARouterBean>>()
    //Group 缓存
    //Map<moduleName, "ARouter$$Path$$moduleName.class>
    var mAllGroupMap = mutableMapOf<String,String>()
    private fun Messager.print(msg: String) {
        printMessage(Diagnostic.Kind.NOTE, msg);
    }


    override fun init(processingEnv: ProcessingEnvironment?) {
        super.init(processingEnv)

        //初始化
        processingEnv?.apply {
            MSG = messager
            MSG.print("路由注解处理器初始化开始")
            mElement = elementUtils
            mTypes = typeUtils
            mFiler = filer
            //获取build.gradle中配置的信息
            this@ARouterProcessor.options = this.options.get(AProcessorConfig.OPTIONS)?.toString()
            MSG.print(">>>>>>>>>>>>>>>>>>>>>> options:${this@ARouterProcessor.options}")
            MSG.print(">>>>>>>>>>>>>>>>>>>>>> aptPackage:$aptPackage")
            if (options != null && aptPackage != null){
                MSG.print("APT 环境搭建完成....")
            }else{
                MSG.print("APT 环境有问题，请检查 options 与 aptPackage 为null...")
            }
        }

    }

    /**
     * 开始执行
     */
    override fun process(
        typeElementSet: MutableSet<out TypeElement>?,
        roundEnvironment: RoundEnvironment?
    ): Boolean {
        typeElementSet?.let {
            if (it.isEmpty()){
                MSG.print("未发现相关设置")
                return false
            }
            //获取路由注解集合
            var arouterElements = roundEnvironment?.getElementsAnnotatedWith(ARouter::class.java)
            //获取activity类型
            var activityType= mElement.getTypeElement(ACTIVITY_PACKAGE)
            //获取fragment类型
            var fragmentType= mElement.getTypeElement(Fragment_PACKAGE)
            //获取fragment类型
            var callType= mElement.getTypeElement(CALL_PACKAGE)
            //获取类信息
            var activityMirror = activityType.asType()
            var fragmentMirror = fragmentType.asType()
            var callMirror = callType.asType()
            arouterElements?.let {
                it.forEach {
                    //获取注解标注的类名称
                    var className = it.simpleName.toString()
                    MSG.print("============${className}=========")
                    //获取注解
                    var aRouter = it.getAnnotation(ARouter::class.java)
                    //组装路由对象
                    var routerBean = ARouterBean(1,aRouter.path,this@ARouterProcessor.options!!,null).apply {
                        this.element = it
                    }
                    //获取注解标注类的信息
                    var elementMirror = it.asType()
                    if (mTypes.isSubtype(elementMirror,activityMirror)){
                        //是Activity的子类
                        routerBean.type = ACTIVITY
                        MSG.print("============是Activity=========")
                    }else if (mTypes.isSubtype(elementMirror,fragmentMirror)) {
                        //是Activity的子类
                        routerBean.type = FRAGMENT
                        MSG.print("============是Fragment=========")
                    }else if (mTypes.isSubtype(elementMirror,callMirror)) {
                        routerBean.type = CALL
                    }else{
                        throw RuntimeException("@ARouter注解目前仅限用于Activity/Fragment/Call实现类之上");
                    }
                    if (checkRouterPath(routerBean)){
                        MSG.print("路由设置检测：group:${routerBean.group}  path:${routerBean.path}")
                        var aRouterBeans = mAllPathMap[routerBean.group]
                        if (null == aRouterBeans||aRouterBeans.isEmpty()){
                            aRouterBeans = mutableListOf<ARouterBean>()
                            aRouterBeans.add(routerBean)
                            mAllPathMap.put(routerBean.group,aRouterBeans)
                        }else{
                            aRouterBeans.add(routerBean)
                        }
                    }
                }
                //定义生成APT文件的实现接口 IARouterPath IARouterGroup
                var pathType = mElement.getTypeElement(AROUTER_API_PATH)
                var groupType = mElement.getTypeElement(AROUTER_API_GROUP)
                //生成IARouterPath接口实现类
                createPathImplClass()
//                MSG.print(mAllGroupMap)
                if (!mAllGroupMap.isEmpty()){
                    mAllGroupMap.keys.forEach {
                        MSG.print("modle:${it}  class:${mAllGroupMap[it]}")
                    }
                    createGroupImplClass()
                }
            }

        }

   return true
    }
//创建group辅助类
    private fun createGroupImplClass() {

//        class ARouterGroupAPP:IARouterGroup {
//            override fun getGroupCache(map: HashMap<String, Class<out IARouterPath>>):
//                    HashMap<String, Class<out IARouterPath>> {
//                map["app"] = `ARouter$$Path$$app`::class.java
//                return map
//            }
//        }
        //1.创建方法
        var clz =  Class::class.java.asClassName().parameterizedBy(WildcardTypeName.producerOf(ClassName(API_PACKAGE,IAROUTERPATH)))
        var funSpecBuilder = FunSpec.builder(METHOD_AROUTER_GROUP)//方法名
            .addModifiers(KModifier.OVERRIDE)//添加override关键子
            .addParameter("map",    HashMap::class.java.asClassName().parameterizedBy(
                String::class.asTypeName(),//String
                Class::class.java.asClassName().parameterizedBy(//Class<out IRouterPath>
                    WildcardTypeName.producerOf(ClassName(API_PACKAGE,IAROUTERPATH))
                )
            ))
            //asClassName 是全路径java.lang.String
            //asTypeName 是String
            .returns(HashMap::class.java.asClassName().parameterizedBy(
                String::class.asTypeName(),//String
                Class::class.java.asClassName().parameterizedBy(//Class<out IRouterPath>
                    WildcardTypeName.producerOf(ClassName(API_PACKAGE,IAROUTERPATH))
                )
            ))
        mAllGroupMap.forEach { t, u ->
            // map["app"] = `ARouter$$Path$$app`::class.java
            //2.创建方法体
            funSpecBuilder.addStatement(
                """
                    |map[%S] = %T::class.java
                    |
                """.trimMargin(),
                t,
                ClassName(aptPackage!!,u)
            )
        }
        funSpecBuilder.addStatement("return %N", "map")
        //3.创建类
        //继承的接口
        var superInterface = ClassName(API_PACKAGE,IAROUTERGROUP)
        //生成的apt类文件名称
        var groupName = String.format(GROUP_FILE_NAME+this@ARouterProcessor.options)
        var typeSpec = TypeSpec.classBuilder(groupName)//创建类
            .addFunction(funSpecBuilder.build())//添加方法
            .addSuperinterface(superInterface)//继承接口
            .build()
        //创建文件
        FileSpec.builder(aptPackage!!,groupName)
            .addType(typeSpec)
            .build()
            .writeTo(mFiler)
        MSG.print("创建文件成功：${groupName}")

    }
//创建PAth辅助类
    private fun createPathImplClass() {
        if (null == mAllPathMap || mAllPathMap.isEmpty()){
            //没有数据
            return
        }
        var fileName = ""
//        class ARouterPathAPP:IARouterPath {
//            override fun getPathCache(map:HashMap<String, ARouterBean>) {
//                map["activityName"]= ARouterBean(
//                    type = ACTIVITY,
//                    path = "/app/MainActivity",
//                    group = "app",
//                    clazz = MainActivity::class.java
//
//                )
//            }
//        }
        //1.创建方法 getPathCache()
        val funSpecBuilder = FunSpec.builder(METHOD_AROUTER_PATH)//方法名称
            .addModifiers(KModifier.OVERRIDE)//添加override关键字
            .returns(HashMap::class.parameterizedBy(String::class,ARouterBean::class))
            .addParameter("map",
                //HashMap<String, ARouterBean>
            HashMap::class.parameterizedBy(String::class,ARouterBean::class))

        //2.为方法添加代码
        //                RouteCacheData.routerPathCache["path"]= ARouterBean(
//                    type = ACTIVITY,
//                    path = "/app/MainActivity",
//                    group = "app",
//                    clazz = MainActivity::class.java
//
//                )
        funSpecBuilder.addStatement("//随便添加个注释不然返回值老是= map")
           mAllPathMap.forEach { t, u ->
            u.forEach { aRouterBean ->
                //注意参数类型别写错了 type Int 对应L不是T 不是T
                funSpecBuilder.addStatement(
                    """
                    |map[%S] = ARouterBean(
                    |   type = %L,
                    |   path = %S,
                    |   group = %S,
                    |   clazz = %T::class.java
                    |)
                    |
                """.trimMargin(),
                    aRouterBean.path,
                    aRouterBean.type,
                    aRouterBean.path,//path
                    aRouterBean.group,//group
                    aRouterBean.element!!.asType()//clazz
                )
            }
            funSpecBuilder.addStatement("return %N", "map")
            //3.创建类
            //继承的接口
            var superInterface = ClassName(API_PACKAGE,IAROUTERPATH)
            //生成的apt类文件名称
            fileName = String.format(PATH_FILE_NAME+t)
            var typeSpec = TypeSpec.classBuilder(fileName)//创建类
                .addFunction(funSpecBuilder.build())//添加方法
                .addSuperinterface(superInterface)//继承接口
                .build()
            //创建文件
            FileSpec.builder(aptPackage!!,fileName)
                .addType(typeSpec)
                .build()
                .writeTo(mFiler)
            MSG.print("创建文件成功：${fileName}")
        }
        mAllGroupMap[this@ARouterProcessor.options!!] = fileName

    }

    //判断路由注解配置的路径是否符合规则
    private fun checkRouterPath(bean:ARouterBean):Boolean{
        if (bean.group == null){
            MSG.printMessage(Diagnostic.Kind.ERROR,"build.gradle中必须配置javaCompileOptions")
            return false
        }
        if (bean.path == null || !bean.path.startsWith("/") ||
            bean.path.split("/").size<3
            || bean.path.lastIndexOf("/") == 0){
            MSG.printMessage(Diagnostic.Kind.ERROR,"ARouter path 格式必须是 /xxx/xxxx ...  错误配置" +
                    "${bean.path}")
            return false
        }
       return true
    }
}